from PyQt5.QtCore import QThread, pyqtSignal
from socket import AF_INET, SOCK_STREAM, socket
from Data_Pack import myPack, myRecv
from PIL import Image
from torch import save as T_save, load as T_load


class FC_HDRM_Work(QThread):
    sig_confin = pyqtSignal()
    sig_dsfin = pyqtSignal()
    sig_samfin = pyqtSignal()
    sig_wffin = pyqtSignal()
    sig_nno1fin = pyqtSignal()
    sig_nns1fin = pyqtSignal()
    sig_nngs1fin = pyqtSignal()
    sig_nngd1fin = pyqtSignal()
    sig_nno2fin = pyqtSignal()
    sig_nns2fin = pyqtSignal()
    sig_nngd2fin = pyqtSignal()

    def __init__(self):
        super(FC_HDRM_Work, self).__init__()
        # 状态变量 - 线程控制
        self.thr_state = 0
        self.thr_msg = None
        # 状态变量 - 网络连接
        self.tcp_on = False
        self.tcp_ip = None
        self.tcp_port = None
        self.tcp_text = None
        self.sc_c = socket(AF_INET, SOCK_STREAM)
        self.wsec_c = 15.0
        self.sc_c.settimeout(self.wsec_c)
        # 状态变量 - 数据读取
        self.dset_on = False
        self.dset_path = ''
        self.dset_strain = None
        self.dset_stest = None
        self.dset_svalid = None
        self.dset_ltrain = None
        self.dset_ltest = None
        self.dset_lvalid = None
        # 状态变量 - 样本显示
        self.sam_ok = False
        self.sam_index = None
        self.sam_count = None
        self.sam_fromS = False
        self.sam_img = None
        self.sam_str = ''
        # 状态变量 - 权重文件
        self.nn_wsave = False
        self.nn_wfok = False
        self.nn_wpath = ''
        self.nn_wfile = None
        # 状态变量 - 网络运行参数（模式1）
        self.nno1_dset = 0
        self.nno1_back = False
        self.nno1_epoch = 1
        self.nno1_acur = False
        self.nno1_loss = False
        self.nno1_ok = False
        self.nns1_ok = False
        # 状态变量 - 网络状态
        self.nn_workon = False
        self.nn_ostate = 1
        self.nn_nowepoch = 0
        self.nn_nowbatch = 0
        self.nn_a1_ok = False
        self.nn_l1_ok = False
        self.nn_a2_ok = False
        self.nn_l2_ok = False
        # 状态变量 - 网络数据（模式1）
        self.a1_nums = None
        self.a1_cors = None
        self.a1_rates = None
        self.a1_losses = None
        self.a1_depoch = 1
        # 状态变量 - 网络数据（模式2）
        self.nno2_ok = False
        self.nns2_ok = False
        self.a2_nums = None
        self.a2_cors = None
        self.a2_rates = None
        self.a2_losses = None
        self.a2_depoch = 1

    def run(self):
        # 0:初始化状态
        # 1:网络连接
        # 2:数据读取
        # 3:样本展示
        # 4:存取权重文件
        # 5:请求神经网络运作（模式1）
        # 6:请求神经网络中止（模式1）
        # 7:请求查看网络状态（模式1）
        # 8:请求获取网络数据（模式1）
        # 9:请求神经网络运作（模式2）
        # 10:请求神经网络停止（模式2）
        # 11:请求获取网络数据（模式2）
        if self.thr_state == 1:
            self.Ser_con()
            self.sig_confin.emit()
        elif self.thr_state == 2:
            self.Dset_init()
            self.sig_dsfin.emit()
        elif self.thr_state == 3:
            self.Sam_get()
            self.sig_samfin.emit()
        elif self.thr_state == 4:
            self.Wfile_sl()
            self.sig_wffin.emit()
        elif self.thr_state == 5:
            self.NN_opa1()
            self.sig_nno1fin.emit()
        elif self.thr_state == 6:
            self.NN_stop1()
            self.sig_nns1fin.emit()
        elif self.thr_state == 7:
            self.NN_gs1()
            self.sig_nngs1fin.emit()
        elif self.thr_state == 8:
            self.NN_gd1()
            self.sig_nngd1fin.emit()
        elif self.thr_state == 9:
            self.NN_opa2()
            self.sig_nno2fin.emit()
        elif self.thr_state == 10:
            self.NN_stop2()
            self.sig_nns2fin.emit()
        elif self.thr_state == 11:
            self.NN_gd2()
            self.sig_nngd2fin.emit()

    def Ser_con(self):
        if self.tcp_on:
            self.tcp_text = {'cmd': 'close'}
            self.sc_c.sendall(myPack(self.tcp_text))
            self.sc_c.close()
            self.sc_c = socket(AF_INET, SOCK_STREAM)
            self.sc_c.settimeout(self.wsec_c)
            self.thr_msg = '已断开与服务端的连接'
            self.tcp_on = False
            self.dset_on = False
            self.nn_workon = False
        else:
            try:
                self.sc_c.connect((self.tcp_ip, self.tcp_port))
            except Exception as e:
                self.thr_msg = e
                self.tcp_on = False
            else:
                self.thr_msg = '与服务端已建立连接'
                self.tcp_on = True

    def Dset_init(self):
        self.tcp_text = {'cmd': 'loaddset', 'droot': self.dset_path}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.dset_on = self.tcp_text['dset_on']
        except Exception as e:
            self.thr_msg = e
            self.dset_on = False
        else:
            if self.dset_on:
                self.thr_msg = '数据集载入成功！'
                self.dset_ltrain = self.tcp_text['ltrain']
                self.dset_ltest = self.tcp_text['ltest']
                self.dset_lvalid = self.tcp_text['lvalid']
            else:
                self.thr_msg = '服务端异常'

    def Sam_get(self):
        self.tcp_text = {'cmd': 'samget',
                        'index': self.sam_index,
                        'count': self.sam_count}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.sam_img = self.tcp_text['img']
            self.sam_str = self.tcp_text['str']
        except Exception as e:
            self.thr_msg = e
            self.sam_ok = False
        else:
            self.sam_img = self.sam_img.toqpixmap()
            self.sam_ok = True

    def Wfile_sl(self):
        self.tcp_text = {'cmd': 'slwfile', 'nn_wsave': self.nn_wsave}
        try:
            if not self.nn_wsave:
                self.nn_wfile = T_load(self.nn_wpath)
                self.tcp_text['nn_wfile'] = self.nn_wfile
            self.sc_c.sendall(myPack(self.tcp_text))
            self.tcp_text = myRecv(self.sc_c)
            if self.nn_wsave:
                self.nn_wfile = self.tcp_text['nn_wfile']
                T_save(self.nn_wfile, self.nn_wpath)
            self.nn_wfok = self.tcp_text['nn_wfok']
        except Exception as e:
            self.thr_msg = e
            self.nn_wfok = False
        else:
            if self.nn_wsave:
                self.thr_msg = '权重文件保存成功！'
            else:
                self.thr_msg = '权重文件读取成功！'

    def NN_opa1(self):
        self.tcp_text = {'cmd': 'nnopa1',
                        'nno1_dset': self.nno1_dset,
                        'nno1_back': self.nno1_back,
                        'nno1_epoch': self.nno1_epoch,
                        'nno1_acur': self.nno1_acur,
                        'nno1_loss': self.nno1_loss}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nno1_ok = self.tcp_text['nno1_ok']
            self.nn_workon = self.tcp_text['nn_workon']
            self.nn_ostate = self.tcp_text['nn_ostate']
        except Exception as e:
            self.thr_msg = e
            self.nno1_ok = False
        else:
            if self.nno1_ok:
                self.thr_msg = '神经网络已开始运作（模式1）！'
            else:
                self.thr_msg = '服务端已在工作中'

    def NN_stop1(self):
        self.tcp_text = {'cmd': 'nnstop1'}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nns1_ok = self.tcp_text['nns1_ok']
            self.nn_workon = self.tcp_text['nn_workon']
            self.nn_ostate = self.tcp_text['nn_ostate']
        except Exception as e:
            self.thr_msg = e
            self.nns1_ok = False
        else:
            if self.nns1_ok:
                self.thr_msg = '已下达中止命令（模式1）！'
            elif self.nn_workon:
                self.thr_msg = '服务端未在该模式'
            else:
                self.thr_msg = '服务端未在工作中'

    def NN_gs1(self):
        self.tcp_text = {'cmd': 'nngs1'}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nn_workon = self.tcp_text['nn_workon']
            self.nn_ostate = self.tcp_text['nn_ostate']
            self.nn_nowepoch = self.tcp_text['nn_nowepoch']
            self.nn_nowbatch = self.tcp_text['nn_nowbatch']
        except Exception as e:
            self.thr_msg = e
        else:
            self.thr_msg = '工作中: {}, 模式: {},epoch: {:0>4d}, batch: {:0>4d}'.format(
                self.nn_workon, self.nn_ostate, self.nn_nowepoch + 1, self.nn_nowbatch + 1)

    def NN_gd1(self):
        self.tcp_text = {'cmd': 'nngd1'}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nn_a1_ok = self.tcp_text['nn_a1_ok']
            if self.nn_a1_ok:
                self.a1_nums = self.tcp_text['a1_nums']
                self.a1_cors = self.tcp_text['a1_cors']
                self.a1_rates = self.tcp_text['a1_rates']
            self.nn_l1_ok = self.tcp_text['nn_l1_ok']
            if self.nn_l1_ok:
                self.a1_losses = self.tcp_text['a1_losses']
            self.a1_depoch = self.tcp_text['a1_depoch']
        except Exception as e:
            self.thr_msg = e
        else:
            self.thr_msg = 'Accuracy数据: {}, Loss数据: {}'.format(
                                        self.nn_a1_ok, self.nn_l1_ok)

    def NN_opa2(self):
        self.tcp_text = {'cmd': 'nnopa2'}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nno2_ok = self.tcp_text['nno2_ok']
            self.nn_workon = self.tcp_text['nn_workon']
            self.nn_ostate = self.tcp_text['nn_ostate']
        except Exception as e:
            self.thr_msg = e
            self.nno2_ok = False
        else:
            if self.nno2_ok:
                self.thr_msg = '神经网络已开始运作（模式2）！'
            else:
                self.thr_msg = '服务端已在工作中'

    def NN_stop2(self):
        self.tcp_text = {'cmd': 'nnstop2'}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nns2_ok = self.tcp_text['nns2_ok']
            self.nn_workon = self.tcp_text['nn_workon']
            self.nn_ostate = self.tcp_text['nn_ostate']
        except Exception as e:
            self.thr_msg = e
            self.nns2_ok = False
        else:
            if self.nns2_ok:
                self.thr_msg = '已下达中止命令（模式2）！'
            elif self.nn_workon:
                self.thr_msg = '服务端未在该模式'
            else:
                self.thr_msg = '服务端未在工作中'

    def NN_gd2(self):
        self.tcp_text = {'cmd': 'nngd2'}
        self.sc_c.sendall(myPack(self.tcp_text))
        try:
            self.tcp_text = myRecv(self.sc_c)
            self.nn_a2_ok = self.tcp_text['nn_a2_ok']
            if self.nn_a2_ok:
                self.a2_nums = self.tcp_text['a2_nums']
                self.a2_cors = self.tcp_text['a2_cors']
                self.a2_rates = self.tcp_text['a2_rates']
            self.nn_l2_ok = self.tcp_text['nn_l2_ok']
            if self.nn_l2_ok:
                self.a2_losses = self.tcp_text['a2_losses']
            self.a2_depoch = self.tcp_text['a2_depoch']
        except Exception as e:
            self.thr_msg = e
        else:
            self.thr_msg = 'Accuracy数据: {}, Loss数据: {}'.format(
                                        self.nn_a2_ok, self.nn_l2_ok)
